using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using ActivateYourGlutes.Infrastructure;
using ActivateYourGlutes.Infrastructure.Logging;
using ActivateYourGlutes.Model;
using ActivateYourGlutes.Model.Providers;
using ActivateYourGlutes.Payloads.Goal;
using Goal=ActivateYourGlutes.Model.Contracts.Goal;

namespace ActivateYourGlutes.Controllers
{
    public partial class GoalController : LocalisingController
    {
        private readonly IGoalProvider _goalProvider;
        private readonly IMeasurementTypeProvider _measurementTypeProvider;

        public GoalController(
            IGoalProvider goalProvider,
            IAccountProvider accountProvider,
            IMeasurementTypeProvider measurementTypeProvider,
            ILogger logger) : base(accountProvider, logger)
        {
            _goalProvider = goalProvider;
            _measurementTypeProvider = measurementTypeProvider;
        }

        [Authorize(Roles = "User")]
        public virtual ActionResult Index()
        {
            var account = CurrentAccount;
            ViewData.Model = new IndexPayload
                                 {
                                     AchievedGoals = _goalProvider.RecentlyAchievedGoals(account),
                                     ActiveGoals = _goalProvider.ActiveGoals(account)
                                 };

            return View();
        }

        [Authorize(Roles = "User")]
        public virtual ActionResult Create()
        {
            var goalTemplate = _goalProvider.Template(CurrentAccount);
            SetCreateViewData(goalTemplate);
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [Authorize(Roles = "User")]
        [ValidateAntiForgeryToken]
        public virtual ActionResult Create([Bind(Exclude = "GoalId,MeasurementType,LocalisedValue")] Goal goal, int measurementType, int localisedValue)
        {
            // Given only binding errors will trigger this I'm not sure how best to unit test this code
            if (!ModelState.IsValid)
            {
                SetCreateViewData(goal);
                return View();
            }

            var type = _measurementTypeProvider.MeasurementTypes(CurrentAccount).Where(mt => mt.MeasurementTypeId == measurementType).FirstOrDefault();
            goal.Active = true;
            goal.MeasurementType = type;
            goal.LocalisedValue = localisedValue;
            try
            {
                _goalProvider.Add(goal, CurrentAccount, LocaleSettings);
            }
            catch(ValidationException ex)
            {
                SetCreateViewData(goal);
                ex.AddToModelState(ViewData.ModelState);
                return View();
            }

            return RedirectToAction("Index");
        }

        private void SetCreateViewData(Goal goal)
        {
            var decrease = new SelectListItem { Selected = goal.DecreaseTo, Text = "Decrease to", Value = true.ToString() };
            var increase = new SelectListItem { Selected = !goal.DecreaseTo, Text = "Increase to", Value = false.ToString() };
            ViewData.Model = new CreatePayload
                                 {
                                     Goal = goal,
                                     IncreaseDecrease = new List<SelectListItem>(new[] { decrease, increase }),
                                     MeasurementTypes = _measurementTypeProvider.MeasurementTypes(CurrentAccount)
                                 };
        }

        [Authorize(Roles = "User")]
        public virtual ActionResult Detail(int id)
        {
            try
            {
                var goal = _goalProvider.GetGoalById(CurrentAccount, id);
                ViewData.Model = goal;
                return View();
            }
            catch (AuthorizationException)
            {
                return this.RedirectToUnauthorized();
            }
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [Authorize(Roles = "User")]
        [ValidateAntiForgeryToken]
        public virtual ActionResult Deactivate(int id)
        {
            try
            {
                var goal = _goalProvider.GetGoalById(CurrentAccount, id);
                _goalProvider.Deactivate(CurrentAccount, goal);
                return RedirectToAction("Index");
            }
            catch (AuthorizationException)
            {
                return this.RedirectToUnauthorized();
            }            
        }
    }
}
